(* The Cardigan AST *)

(* Seperators *)
type sep = Space | Tab | Backslash | Nosep;;

(* Operators *)
type op = Add | Sub | Mult | Div | Power | Mod | NotEq | Eq | Greater | Less | Gte | Lte | And | Or | Inc | Dec;;

(* Identifier *) (*

WORKING ON THIS:
type firstChar = Letter | Underscore;;
type chars = Letter | Underscore | Digit;;
type iden = 
	Iden of firstChar * chars list;;

let rec string_of_iden = function
	Iden(f, c) ->
		(match f with 
			Letter -> char | *)
type iden = string;;

(* Types *) (*
type primTp = Bool | Int | Float | String | Char
type derTp = Struct | Collection | Enum 
type types = Bool | Int | Float | String | Char | Struct | Collection | Enum;;*)

(* Types *)
(* type types = Bool | Int | Float | String | Char | Struct | Collection | Enum *)

(* Literals *)
type lit = 
	Bool of bool
|	Int of int
|	Float of float
|	String of string
|	Struct of iden * iden
|	Collection of iden * int
|	Enum of iden * iden;;

let string_of_lit = function
	Bool(l) -> string_of_bool l
|	Int(l) -> string_of_int l
|	Float(l) -> string_of_float l
|	String(l) -> l
|	Struct(i1, i2) -> i1 ^ "." ^ i2
|	Collection(i, n) -> i ^ "[" ^ string_of_int n ^ "]"
|	Enum(i1, i2) -> i1 ^ "." ^ i2;;


(* Expression *)
type expr =
	Sep of sep * expr * sep
|	Id of iden
|	Literal of lit
|	StructD of iden * expr
|	CollectionD of expr list
|	EnumD of expr list
|	Declare of string * expr
|	Assign of iden * sep * expr
|	Op of expr * op * expr
|	Call of string * expr list
|	Noexpr;;

let rec string_of_expr = function
	Sep(s1, e, s2) ->
		(match s1 with Space -> " " | Tab -> "	" | Backslash -> "\\" | Nosep -> "") ^ 
		string_of_expr e ^
		(match s2 with Space -> " " | Tab -> "	" | Backslash -> "\\" | Nosep -> "")	
|	Id(s) -> s
|	Literal(l) -> string_of_lit l
|	StructD(i, e) -> i ^ ":" ^ string_of_expr e
|	CollectionD(e) ->
		"[" ^ String.concat ", " (List.map string_of_expr e) ^ "]"
|	EnumD(i) -> "|" ^ String.concat ", " (List.map string_of_expr i) ^ "|"
|	Declare(s, e) -> s ^ string_of_expr e 
|	Assign(i, s, e) -> 
		i ^ (match s with Space -> " " | Tab -> "	" | Backslash -> "\\" | Nosep -> "") ^ "=" ^ 
		string_of_expr e
|	Op(e1, op, e2) -> string_of_expr e1 ^
		(match op with Add -> "+" | Sub -> "-" | Mult -> "*" | Div -> "/" | Power -> "^" | Mod -> "%" | NotEq -> "!" | Eq -> "==" | Greater -> ">" | Less -> "<" | Gte -> ">=" | Lte -> "<=" | And -> " and " | Or -> " or " | Inc -> "++" | Dec -> "--") ^
		string_of_expr e2
|	Call(f, e) ->
      f ^ "(" ^ String.concat ", " (List.map string_of_expr e) ^ ")"
|	Noexpr -> "";;


(*Statement *)
type stmt =
	Expr of expr
|	Block of stmt list
|	If of expr * stmt * stmt
|	While of expr * stmt
|	For of expr * expr * expr * stmt
|	Rules of char * expr * stmt
|	Return of expr
|	Nostmt;;

let rec string_of_stmt = function
	Expr(e) -> string_of_expr e ^ "\n"
|	Block(stmts) -> 
|	Nostmt = ""





(* Function Declarations *)
type func_decl = {
    fname : iden;
    args : expr list;
    body : stmt list;
  };;

type program = string list * func_decl list;;


(* Fancy Parts I started with without creating anything above *)

type cardiganProgram =
	Stmt of stmt * spaces * stmt * endline
|	Block of cardiganProgram list
